/**
 * cn.ucox.web.framework.util.PropertiesKit
 *
 * @author chenw
 * @create 16/3/4.18:18
 * @email javacspring@hotmail.com
 */

package cn.com.oceansoft.framework.kits;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * 全局属性文件工具
 *
 * @author chenw
 * @create 16/3/4 18:18
 * @email javacspring@gmail.com
 */
public class PropertiesKit {

    private static final Logger logger = LoggerFactory.getLogger(PropertiesKit.class);
    private static HashMap<String, Properties> mProperties;//全部配置文件集合
    private static HashMap<String, Object> mConfigItems; //全部配置项
    private static HashMap<String, HashMap<String, Object>> mCatalogGroups; //配置项按前缀分组
//    private static HashMap<String,HashMap<String,Object>> mFileGroup;

    private PropertiesKit() {
        mProperties = new HashMap<>();
        mConfigItems = new HashMap<>();
        mCatalogGroups = new HashMap<>();
    }

    /**
     * 注册属性配置文件
     *
     * @param property 属性配置路径
     */
    public PropertiesKit build(String property) {
        synchronized (property) {
            String backup = property;
            logger.info("===================初始化属性文件{}.properties开始===================", property);
            if (property.endsWith(".properties")) {
                property = property.substring(property.lastIndexOf("/") + 1, property.lastIndexOf("."));
            }
            String propertiesKey = property.trim().toLowerCase();
            if (mProperties.containsKey(propertiesKey))
                throw new RuntimeException(String.format("配置文件[{%s}]已存在!", property));
            Properties catalogProperties = loadProperties(backup);
            mProperties.put(property, catalogProperties);
            for (Object _key : catalogProperties.keySet()) {
                if (null != _key) {
                    mConfigItems.put(_key.toString(), catalogProperties.get(_key));
                    mConfigItems.put(String.format("%s:%s", property, _key.toString()), catalogProperties.get(_key));
                }
                logger.debug("{}={}", _key, catalogProperties.get(_key));
            }
            logger.debug("===================初始化属性文件{}结束===================", property);
        }
        return PropertiesUtilHolder.INSTANCE;
    }

    public PropertiesKit build(String... properties) {
        for (String property : properties) {
            build(property);
        }
        return PropertiesUtilHolder.INSTANCE;
    }

    private static final class PropertiesUtilHolder {
        private static final PropertiesKit INSTANCE = new PropertiesKit();
    }

    public static final PropertiesKit getInstance() {
        return PropertiesUtilHolder.INSTANCE;
    }

    /**
     * 加载属性配置文件
     *
     * @param propertiesPath 属性文件路径
     * @return Properties
     */
    private Properties loadProperties(String propertiesPath) {
        Properties props = new Properties();

        InputStream in = getClass().getResourceAsStream(propertiesPath);
        try {
            props.load(in);
//            for (Object key : props.keySet()) {
//                mConfigItems.put(key.toString(), props.get(key));
//            }
            return props;
        } catch (IOException e) {
            logger.error("加载配置文件[{}]失败,错误:{}", propertiesPath, e.getMessage());
            throw new RuntimeException("加载配置文件错误!", e);
        } finally {
            try {
                in.close();
            } catch (IOException e) {
                logger.error("关闭配置文件文件流失败!,错误:{}", e.getMessage());
            }
        }
    }

    public HashMap<String, Object> loadAll() {
        if (null == mConfigItems) {
            throw new RuntimeException("请先调用build方法注册属性配置文件");
        }
        return mConfigItems;
    }

    /**
     * 获取配置项值
     *
     * @param key KEY名称
     * @param <T> 返回值类型
     * @return 返回值
     */
    public <T> T getValue(String key) {
        if (null == mConfigItems) {
            throw new RuntimeException("请先调用build方法注册属性配置文件");
        }
        Object obj = mConfigItems.get(key);
        return null == obj ? null : (T) mConfigItems.get(key);
    }

    /**
     * 清除相同前缀配置项
     *
     * @param group 前缀(组)名称
     */
    public void clearGroup(String group) {
        logger.debug("命中缓存属性文件集合:{},共{}项", group, mCatalogGroups.get(group).size());
        mCatalogGroups.remove(group);
    }

    /**
     * 根据前缀加载配置信息集合
     * 已读取过的文件将缓存
     *
     * @param prefix 配置前缀
     * @return HashMap<String,String>
     */
    public HashMap<String, Object> loadGroup(String prefix) {
        if (null == mCatalogGroups) {
            throw new RuntimeException("请先调用build方法注册属性配置文件");
        }
        if (mCatalogGroups.containsKey(prefix)) {
            logger.debug("命中缓存属性文件集合:{},共{}项", prefix, mCatalogGroups.get(prefix).size());
            return mCatalogGroups.get(prefix);
        } else {
            HashMap<String, Object> groupItems = new HashMap<>();
            mConfigItems.keySet().stream()
                    .filter(_key -> _key.startsWith(prefix))
                    .forEach(_key -> groupItems.put(_key, mConfigItems.get(_key)));
//            if (groupItems.size() > 0) {
                mCatalogGroups.put(prefix, groupItems);
                logger.debug("创建缓存属性文件集合:{},共{}项", prefix, mCatalogGroups.get(prefix).size());
//            }
        }
        return mCatalogGroups.get(prefix);
    }

    public HashMap<String, Object> loadFile(String properties) {
        HashMap<String, Object> oldProps = loadGroup(properties);
        HashMap<String, Object> newProps = new HashMap<>(oldProps.size());
        for (Map.Entry<String, Object> entry : oldProps.entrySet()) {
            String key = entry.getKey();
            newProps.put(key.replaceAll(String.format("%s:", properties), ""), entry.getValue());
        }
        oldProps.clear();
        oldProps.putAll(newProps);
        newProps.clear();
        return oldProps;
    }

    public void clear() {
        if (null == mProperties) {
            throw new RuntimeException("请先调用build方法注册属性配置文件");
        }
        mProperties.values().forEach(Properties::clear);
        mProperties.clear();
        mConfigItems.clear();
        mCatalogGroups.values().forEach(HashMap::clear);
        mCatalogGroups.clear();
        mProperties = null;
        mConfigItems = null;
        mCatalogGroups = null;
        logger.info("===================清除属性配置成功===================");
    }
}
